{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href=\"https://colab.research.google.com/gist/iamdaniele/84cca60019384c4159df28e14e2dc61c/toolhouse-llamaindex-workflow.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sales Prospecting Workflow with Toolhouse\n",
    "\n",
    "In this notebook you'll learn how to create a sales prospecting workflow using Toolhouse and LlamaIndex. Sales prospecting allows companies to find the perfect potential customer based on the business's value proposition and target market.\n",
    "\n",
    "The workflow will use a single agent to perform these activities:\n",
    "\n",
    "1. It will ask the agent to determine a business's value proposition by getting the contents of its landing page.\n",
    "1. It will search the internet for prospective customers that may benefit from the business's offerings.\n",
    "1. It will determine the best company to reach out to.\n",
    "1. It will draft a personalized email to the selected company.\n",
    "\n",
    "## Initial setup\n",
    "\n",
    "Let's make sure all the required libraries are present. This example uses Llama 3.2 on Groq, but you can use any the LLMs supported by LlamaIndex."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install llama-index\n",
    "%pip install llama-index-llms-groq\n",
    "%pip install toolhouse"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we'll pass the API keys.\n",
    "\n",
    "To get a Toolhouse API key:\n",
    "\n",
    "1. [Sign up for Toolhouse](https://join.toolhouse.ai) or [sign in](https://app.toolhouse.ai) if you're an existing user.\n",
    "2. If you're a new user, copy the auto-generated API key you'll receive during onboarding. Existing users can get an API key in the [API Keys page](https://app.toolhouse.ai/settings/api-keys).\n",
    "3. Paste the API bey below.\n",
    "\n",
    "To get a Groq API Key, [get access on Groq](https://console.groq.com), then past your API key below.\n",
    "\n",
    "**Important:** store your API keys safely when in production."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "os.environ[\n",
    "    \"TOOLHOUSE_API_KEY\"\n",
    "] = \"Get your Toolhouse API key at https://join.toolhouse.ai\"\n",
    "os.environ[\n",
    "    \"GROQ_API_KEY\"\n",
    "] = \"Get your Groq API key at https://console.groq.com\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Import libraries\n",
    "\n",
    "We're going to import LlamaIndexas and Toolhouse. We then initialize Toolhouse and the Groq LLM."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.llms.groq import Groq\n",
    "from llama_index.core.agent import ReActAgent\n",
    "from llama_index.core.memory import ChatMemoryBuffer\n",
    "from toolhouse import Toolhouse, Provider\n",
    "from llama_index.core.workflow import (\n",
    "    Context,\n",
    "    Event,\n",
    "    StartEvent,\n",
    "    StopEvent,\n",
    "    Workflow,\n",
    "    step,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "llm = Groq(model=\"llama-3.2-11b-vision-preview\")\n",
    "\n",
    "th = Toolhouse(provider=Provider.LLAMAINDEX)\n",
    "th.set_metadata(\"id\", \"llamaindex_agent\")\n",
    "th.set_metadata(\"timezone\", 0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Install Toolhouse tools\n",
    "\n",
    "The agent will require to search the web and get the contents of a page. To allow this, go to your [Toolhouse dashboard](https://app.toolhouse.ai) and install the following tools:\n",
    "\n",
    "- [Get page contents](https://app.toolhouse.ai/store/scraper)\n",
    "- [Web search](https://app.toolhouse.ai/store/web_search)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Workflow\n",
    "\n",
    "The workflow will have four steps; we created an output event for each step to make the sequential aspect clearer.\n",
    "\n",
    "Because Toolhouse integrates directly into LlamaIndex, you can pass the Toolhouse tools directly to the agent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class WebsiteContentEvent(Event):\n",
    "    contents: str\n",
    "\n",
    "\n",
    "class WebSearchEvent(Event):\n",
    "    results: str\n",
    "\n",
    "\n",
    "class RankingEvent(Event):\n",
    "    results: str\n",
    "\n",
    "\n",
    "class LogEvent(Event):\n",
    "    msg: str\n",
    "\n",
    "\n",
    "class SalesRepWorkflow(Workflow):\n",
    "    agent = ReActAgent(\n",
    "        tools=th.get_tools(bundle=\"llamaindex test\"),\n",
    "        llm=llm,\n",
    "        memory=ChatMemoryBuffer.from_defaults(),\n",
    "    )\n",
    "\n",
    "    @step\n",
    "    async def get_company_info(\n",
    "        self, ctx: Context, ev: StartEvent\n",
    "    ) -> WebsiteContentEvent:\n",
    "        ctx.write_event_to_stream(\n",
    "            LogEvent(msg=f\"Getting the contents of {ev.url}…\")\n",
    "        )\n",
    "        prompt = f\"Get the contents of {ev.url}, then summarize its key value propositions in a few bullet points.\"\n",
    "        contents = await self.agent.achat(prompt)\n",
    "        return WebsiteContentEvent(contents=str(contents.response))\n",
    "\n",
    "    @step\n",
    "    async def find_prospects(\n",
    "        self, ctx: Context, ev: WebsiteContentEvent\n",
    "    ) -> WebSearchEvent:\n",
    "        ctx.write_event_to_stream(\n",
    "            LogEvent(\n",
    "                msg=f\"Performing web searches to identify companies who can benefit from the business's offerings.\"\n",
    "            )\n",
    "        )\n",
    "        prompt = f\"With that you know about the business, perform a web search to find 5 tech companies who may benefit from the business's product. Only answer with the names of the companies you chose.\"\n",
    "        results = await self.agent.achat(prompt)\n",
    "        return WebSearchEvent(results=str(results.response))\n",
    "\n",
    "    @step\n",
    "    async def select_best_company(\n",
    "        self, ctx: Context, ev: WebSearchEvent\n",
    "    ) -> RankingEvent:\n",
    "        ctx.write_event_to_stream(\n",
    "            LogEvent(\n",
    "                msg=f\"Selecting the best company who can benefit from the business's offering…\"\n",
    "            )\n",
    "        )\n",
    "        prompt = \"Select one company that can benefit from the business's product. Only use your knowledge to select the company. Respond with just the name of the company. Do not use tools.\"\n",
    "        results = await self.agent.achat(prompt)\n",
    "        ctx.write_event_to_stream(\n",
    "            LogEvent(\n",
    "                msg=f\"The agent selected this company: {results.response}\"\n",
    "            )\n",
    "        )\n",
    "        return RankingEvent(results=str(results.response))\n",
    "\n",
    "    @step\n",
    "    async def prepare_email(self, ctx: Context, ev: RankingEvent) -> StopEvent:\n",
    "        ctx.write_event_to_stream(\n",
    "            LogEvent(msg=f\"Drafting a short email for sales outreach…\")\n",
    "        )\n",
    "        prompt = f\"Draft a short cold sales outreach email for the company you picked. Do not use tools.\"\n",
    "        email = await self.agent.achat(prompt)\n",
    "        ctx.write_event_to_stream(\n",
    "            LogEvent(msg=f\"Here is the email: {email.response}\")\n",
    "        )\n",
    "        return StopEvent(result=str(email.response))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Run the workflow\n",
    "\n",
    "Simply instantiate the workflow and pass the URL of a company to get started."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Getting the contents of https://toolhouse.ai…\n",
      "Performing web searches to identify companies who can benefit from the business's offerings.\n",
      "Selecting the best company who can benefit from the business's offering…\n",
      "The agent selected this company: Cohere\n",
      "Drafting a short email for sales outreach…\n",
      "Here is the email: Subject: Streamline Your LLM Function Calling with Toolhouse\n",
      "\n",
      "Hi [Cohere Team],\n",
      "\n",
      "I noticed Cohere is leading the way in providing enterprise-ready LLM solutions. Given that your Command-r model already supports function calling, I thought you'd be interested in Toolhouse's developer toolkit that could enhance your clients' implementation experience.\n",
      "\n",
      "Toolhouse offers a unified SDK that streamlines LLM function calling across multiple models, including Cohere's. Our platform provides:\n",
      "- Pre-built, production-ready tools that reduce development time\n",
      "- Built-in analytics for easier debugging\n",
      "- A single integration point for multiple LLM tools\n",
      "\n",
      "Would you be open to a 15-minute call to discuss how Toolhouse could help Cohere's enterprise clients implement function calling more efficiently?\n",
      "\n",
      "Best regards,\n",
      "[Name]\n"
     ]
    }
   ],
   "source": [
    "workflow = SalesRepWorkflow(timeout=None)\n",
    "handler = workflow.run(url=\"https://toolhouse.ai\")\n",
    "async for event in handler.stream_events():\n",
    "    if isinstance(event, LogEvent):\n",
    "        print(event.msg)"
   ]
  }
 ],
 "metadata": {
  "colab": {
   "include_colab_link": true,
   "provenance": []
  },
  "kernelspec": {
   "display_name": "Python 3",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
